package client

import (
	"time"
	"cloud_worm/util/unet/usocket"
	"sync"
	"cloud_worm/worm/config"
	"runtime"
	"os"
	"github.com/golang/glog"
	"cloud_worm/worm/client/monitor"
)

const (
	WinIdPath = "C:\\Windows\\System32\\config\\worm"
	UnixIdPath = "/etc/worm"

	UnixBaseWorkDir = "/usr/local/worm"
	WinBaseWorkDir = "C:\\Program Files\\worm"

	WeaponDirName = "weapons"
)

type Agent struct {
	SrvConfigUrl 			string

	IntervalTime 			time.Duration
	HttpIntervalTime 		time.Duration
	HeartBeatTimeout 		time.Duration

	usocket.TlsClient
	PushMsgC 				chan []byte
	CloseC 					chan struct{}

	IsLogin 				bool
	Id 						string
	IdFilePath 				string

	Version 				int
}

var AgentInst 	*Agent
var agentOnec	sync.Once

func init()  {
	agentOnec.Do(func() {
		AgentInst = &Agent{
			HttpIntervalTime: 60,
			Id: "",
			IsLogin: false,

			PushMsgC: make(chan []byte, 1024 * 2),
			CloseC: make(chan struct{}),
		}
	})
}

func (a *Agent) InitAgent(version int) error {
	a.SrvConfigUrl = config.CfgInst.StartConfig.(*config.ClientConfig).ServerSet.RouterURL
	a.HttpIntervalTime = time.Duration(config.CfgInst.StartConfig.(*config.ClientConfig).ServerSet.RouterInterval)

	if runtime.GOOS == "windows" {
		if err := os.MkdirAll(WinIdPath, 0600); err != nil {
			return err
		}
		a.IdFilePath = WinIdPath
	} else {
		if err := os.MkdirAll(UnixIdPath, 0600); err != nil {
			return err
		}
		a.IdFilePath = UnixIdPath
	}
	a.Version = version

	glog.Infof("%v", a)
	return nil
}

func (a *Agent) TryLogin() {
	for {
		if a.IsLogin == true {
			// 第一次连接时候不进入该逻辑，这里表示连接断开了，
			// 需要重连考虑到服务可能无法立即恢复，所以稍微延时一下（socket连接超时时间）
			time.Sleep(a.IntervalTime * time.Second)
		}
		a.IsLogin = false

		// 表明socket连接成功，得到conn套接字，否则一直在请求配置服务器，连接服务。
		a.TryConnect()

		// ReqAgentId 上报id逻辑
		err := a.ReqAgentId()
		if err != nil {
			// ReqAgentId 过程中失败，需要sleep一段时间，重新上报 id
			time.Sleep(a.IntervalTime * time.Second)
			continue
		}

		// 上报 id，正常接受，处理服务端响应
		// 主要是 id 写入文件
		err = a.HandleAgentIdMsg()
		if err == DropByServerErr {
			glog.Errorf("conn exist! can not start..")
			break
		}

		if err == nil {
			a.IsLogin = true
			a.SendVersion()
			glog.Infof("login success, get id: %s", a.Id)
			break
		}

		// 还不行就sleep一段时间继续
		time.Sleep(a.IntervalTime * time.Second)
	}

	if a.IsLogin == true {
		go a.PushMsg()
	}

	return
}

func (a *Agent) TryConnect()  {
	// 如果是重连，需要先断掉连续
	if a.TlsClient.Conn.Conn != nil {
		a.TlsClient.Close()
	}

	for {
		if err := InitConfig(a); err != nil {
			glog.Errorf("get'%d' config error: %s", a.Version, err.Error())

			time.Sleep(a.HttpIntervalTime * time.Second)
			continue
		}

		if err := a.TlsClient.Connect(); err != nil {
			glog.Errorf("connection error: %s", err.Error())

			time.Sleep(a.IntervalTime * time.Second)
			continue
		}

		glog.Info("tls connected.")
		break
	}

	return
}

func (a *Agent) Start(localIP string) error {
	a.TryLogin()

	go a.HandleMsg(localIP)

	monitor.PushMsgC = a.PushMsgC
	if err := a.Monitor(localIP); err != nil {
		return err
	}

	return nil
}